import random
from simcell.genetic.nucleotide import NucleotideFactory
from simcell.cell.rna import Rna

class Dna:
    RNA_PROMOTER = [NucleotideFactory.A, NucleotideFactory.T,
                    NucleotideFactory.A, NucleotideFactory.T,
                    NucleotideFactory.A, NucleotideFactory.T]
    RNA_PROMOTER_LEN = len(RNA_PROMOTER)
    
    RNA_TERMINATOR = [NucleotideFactory.T, NucleotideFactory.T,
                      NucleotideFactory.A, NucleotideFactory.A,
                      NucleotideFactory.T, NucleotideFactory.T]
    RNA_TERMINATOR_LEN = len(RNA_TERMINATOR)

    NUCLEOTIDES = [NucleotideFactory.A, NucleotideFactory.T]
    
    COMPLEMENT_TABLE = {NucleotideFactory.A.name: NucleotideFactory.T,
                        NucleotideFactory.T.name: NucleotideFactory.A}
                                  
    TRANSCRIPTION_TABLE = {NucleotideFactory.A.name: NucleotideFactory.U,
                           NucleotideFactory.T.name: NucleotideFactory.A}
                              
    @classmethod
    def getRandomNucleotide(cls):
        i = random.randint(0, len(Dna.NUCLEOTIDES)-1)
        return Dna.NUCLEOTIDES[i]
    
    @classmethod
    def generateRandomDna(cls, num_nucleotides):
        dna = Dna()
        for x in range(num_nucleotides):
            dna.addNucleotide(Dna.getRandomNucleotide())
        return dna

    @classmethod
    def complementNucleotide(cls, nucleotide):
        return Dna.COMPLEMENT_TABLE[nucleotide.name]
    
    def __init__(self):
        self.strand53 = []
        self.strand35 = []        
        self.strands = self.strand53, self.strand35
        self.composition = {'a':0.0, 't':0.0}

    def __str__(self):
        repr  = "length:%d a:%f t:%f" % (len(self.strand53), 
                                         self.composition['a'] / len(self.strand53), 
                                         self.composition['t'] / len(self.strand53))
        return repr
        
    def __repr__(self):
        repr  = str(self) + "\n"
        repr += "5'" + "".join(map(str, self.strand53)) + "'3\n"
        repr += "3'" + "".join(map(str, self.strand35[::-1])) + "'5"
        return repr
    
    def addNucleotide(self, nucleotide):
        # TODO: introduce copy errors here?
        self.strand53.append(nucleotide)
        self.strand35.insert(0, Dna.complementNucleotide(nucleotide))
        self.composition[nucleotide.name] += 1
        
    def transcriptRna(self):
        """
        Generate Rna molecule.
        Must have promoter and terminator or [] will be returned.
        DNA is considered to be circular.
        """
        # print "-- transcriptRnaM --"
        
        # random select strand
        sense = random.randint(0, 1)
        # print "  sense: %s" % sense
        
        seq = self.strands[sense]
        # print "  seq: %s" % "".join(map(str, seq))
        
        # random select start
        ori_p = random.randint(0, len(seq) - 1)
        # print "  ori_p: %d" % ori_p
        if ori_p > 0:
            seq = seq[ori_p:] + seq[:ori_p]
        # print "  seq: %s" % "".join(map(str, seq))

        # try to transcrip an rna_m
        transcripting = False
        rna_m = Rna()
        for i in range(len(seq)):
            # print "    transcripting %s" % transcripting
            if transcripting:
                # print "    terminator? %s" % "".join(map(str, seq[i:i+Dna.RNA_TERMINATOR_LEN]))
                if seq[i:i+Dna.RNA_TERMINATOR_LEN] == Dna.RNA_TERMINATOR:
                    # print "    terminator found."
                    return rna_m
                    
                rna_m.addNucleotide(Dna.TRANSCRIPTION_TABLE[seq[i].name])
                # print "    rna_m: %s" % "".join(map(str, rna_m))
                
            else:
                # print "    promoter? %s" % "".join(map(str, seq[i-Dna.RNA_PROMOTER_LEN:i]))
                if i >= Dna.RNA_PROMOTER_LEN and seq[i-Dna.RNA_PROMOTER_LEN:i] == Dna.RNA_PROMOTER:
                    # print "    promoter found...%s" % "".join(map(str, seq[i:]))
                    rna_m.addNucleotide(Dna.TRANSCRIPTION_TABLE[seq[i].name])
                    transcripting = True

        # print "    rna_m: -"
        return None
